#include <list>

#include <cstdlib>
#include <cstdio>

#include <stdexcept>
#include <string>
#include <algorithm>
#include <iostream>

#include <memory> // std::allocator

#include <malloc.h> // malloc_trim 如果不强制回收内存，整个程序的运行时间会成倍增长

// 其他 allocator
#include <ext/array_allocator.h>
#include <ext/mt_allocator.h>
#include <ext/debug_allocator.h>
#include <ext/pool_allocator.h>
#include <ext/bitmap_allocator.h>
#include <ext/malloc_allocator.h>
#include <ext/new_allocator.h>

#include "test.h"
#include "print.hpp"

void menu() {
    print(std::cout, 
            "Enter a number for choosing allocator for list: ",
            "1: std::allocator;",
            "2: array_allocator(deprecated) (can't work);",
            "3: mt_allocator(__mt_alloc);",
            "4. debug_allocator (can't work);",
            "5. pool_allocator(__pool_alloc);",
            "6. bitmap_allocator",
            "7. malloc_allocator;",
            "8. new_allocator;",
            "q. end.");
}

// 定义一个可以清空容器的参数
template <typename T, typename TA, template<typename U, typename A> class Container>
void clean(Container<T, TA>& container) {
    Container<T, TA> emptyContainer;
    std::swap(container, emptyContainer);
    // container.swap(emptyContainer);
}

void test_list_with_special_allocator() {
    print("test_list_with_special_allocator()...");
    // list
    std::list<string, std::allocator<string>> c1;
    // std::list<string, __gnu_cxx::array_allocator<string>> c2;
    std::list<string, __gnu_cxx::__mt_alloc<string>> c3;
    // std::list<string, __gnu_cxx::debug_allocator<string>> c4;
    std::list<string, __gnu_cxx::__pool_alloc<string>> c5;
    std::list<string, __gnu_cxx::bitmap_allocator<string>> c6;
    std::list<string, __gnu_cxx::malloc_allocator<string>> c7;
    std::list<string, __gnu_cxx::new_allocator<string>> c8;


    std::cout << "How many Elements: ";
    const long value = get_a_target_long();    

GET_CHOICE:
    menu();
    char option;
    while(std::cin >> option) {
        // clear
        switch (option) {
            case '1':
                clean(c1);
                break;
            case '2':
                // clean(c2);
                print("cannot load it");
                menu();
                continue;
            case '3':
                clean(c3);
                break;
            case '4':
                // clean(c4);
                print("cannot load it");
                menu();
                continue;
            case '5':
                clean(c5);
                break;
            case '6':
                clean(c6);
                break;
            case '7':
                clean(c7);
                break;
            case '8':
                clean(c8);
                break;
            case 'q':
                print("buy");
                return;
            default:
                print("wrong option");
                menu();
                continue;
        }
        // 避免每次运行出现时间成倍增长
        // malloc_trim(0);

        static TimeCounter t;
        for (long i=0; i<value; ++i) {
            string str = get_a_random_string(10);
            switch (option) {
                case '1':
                    c1.push_back(str);
                    // print("size: ", c1.size());
                    break;
                    // case '2':
                    //   // c2.push_back(str);
                    //   print("cannot load it");
                    //   goto GET_CHOICE;
                    // break;
                case '3':
                    c3.push_back(str);
                    break;
                    // case '4':
                    //   // c4.push_back(str);
                    //   print("cannot load it");
                    //   goto GET_CHOICE;
                    //   break;
                case '5':
                    c5.push_back(str);
                    break;
                case '6':
                    c6.push_back(str);
                    break;
                case '7':
                    c7.push_back(str);
                    break;
                case '8':
                    c8.push_back(str);
                    break;
                    // case 'q':
                    //   print("buy!");
                    //   return;
                    // default:
                    //   print("wrong option");
                    //   goto GET_CHOICE;
                    //   break;
            }
        }
        t.endAndShow();
        menu();
    }

}

int main() {
    test_list_with_special_allocator();
    return 0;
}
